package com.crois.barrier.web.plugin.route;

import com.crois.barrier.common.dto.ApiRouteInfo;
import com.crois.barrier.common.enums.PluginEnum;
import com.crois.barrier.common.enums.PluginTypeEnum;
import com.crois.barrier.common.enums.UpstreamStrategyEnum;
import com.crois.barrier.plugin.BarrierPlugin;
import com.crois.barrier.plugin.BarrierPluginChain;
import com.crois.barrier.web.support.ServerWebExchangeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Objects;
import java.util.regex.Pattern;

/**
 * @author Hou Ze Yu
 * @description  route 路由转 requestUrl 处理 纯url请求
 * @date 2020/7/13
 */
public class RouteToRequestUrlPlugin implements BarrierPlugin {

    Logger LOGGER = LoggerFactory.getLogger(RouteToRequestUrlPlugin.class);

    private static final String SCHEME_REGEX = "[a-zA-Z]([a-zA-Z]|\\d|\\+|\\.|-)*:.*";

    static final Pattern schemePattern = Pattern.compile("[a-zA-Z]([a-zA-Z]|\\d|\\+|\\.|-)*:.*");

    @Override
    public Mono<Void> execute(ServerWebExchange exchange, BarrierPluginChain chain) {

        LOGGER.info("[begin invoke  RouteToRequestUrl plugin]");

        // 获取 path
        ApiRouteInfo apiRouteInfo = exchange.getAttribute(ServerWebExchangeUtils.BARRIER_ROUTE_ATTR);

        if (apiRouteInfo==null){

            return chain.execute(exchange);

        }else {

            LOGGER.info("[RouteToRequestUrl Plugin Start invoke]");

            if (!apiRouteInfo.getUpstreamStrategy().equals(UpstreamStrategyEnum.URL_ROUTE.getName())){
                // 如果 是 url route 策略
                return chain.execute(exchange);
            }

            // 得到 uri
            URI uri = exchange.getRequest().getURI();

            boolean encoded = ServerWebExchangeUtils.containsEncodedParts(uri);

            URI routeUri = null;
            try {
                routeUri = new URI(apiRouteInfo.getUrl());
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
             if (Objects.isNull(routeUri)){
                 return chain.execute(exchange);
             }
            if (hasAnotherScheme(routeUri)){
                 // 有其他 scheme
                 exchange.getAttributes().put(ServerWebExchangeUtils.BARRIER_SCHEME_PREFIX_ATTR,routeUri.getScheme());
                 // 创建 新的 uri
                 routeUri = URI.create(routeUri.getSchemeSpecificPart());

                LOGGER.info("routeUri:{}",routeUri);
            }
            // 合并 拼装 url
            URI mergedUrl = UriComponentsBuilder.fromUri(uri).scheme(routeUri.getScheme()).host(routeUri.getHost()).port(routeUri.getPort()).build(encoded).toUri();

            exchange.getAttributes().put(ServerWebExchangeUtils.BARRIER_REQUEST_PATH, mergedUrl);
            LOGGER.info("[执行完成：RouteToRequestUrlPlugin]");
            return chain.execute(exchange);
        }


    }
    // 是否 有其他 scheme
    static boolean hasAnotherScheme(URI uri) {
        return schemePattern.matcher(uri.getSchemeSpecificPart()).matches() && uri.getHost() == null && uri.getRawPath() == null;
    }

    @Override
    public PluginTypeEnum pluginType() {
        return PluginTypeEnum.ROUTE;
    }

    @Override
    public String name() {
        return PluginEnum.ROUTE_TO_REQUEST_URL.getName();
    }

    @Override
    public int order() {
        return PluginEnum.ROUTE_TO_REQUEST_URL.getCode();
    }

    @Override
    public Boolean skip(ServerWebExchange exchange) {
        return false;
    }
}
